var XML2Object = new Class({
	
	xml: null,
	text: null,
	xmlObj: {},
	xmlurl: null,
	root: null,
	
	initialize: function(xmlDom) {
        this.xml = xmlDom;
        this.xmlObj = this._recursive_traverse(this.get_rootNode());
	},
	
	_recursive_traverse: function(node) {
		var obj = {};
		if(this.has_attributes(node)) {
            obj['@attributes'] = {};
			Array.each(this.get_attributes(node), function(attribute, index) {
				obj['@attributes'][this.get_name(attribute)] = this.get_value(attribute);
			}, this);
		} else if (this.get_type(node) == 3){
            obj = this.get_value(node);
        }
		
		if(this.has_childNodes(node)) {
			Array.each(this.get_childElements(node), function(child, index) {
                var nodeName = this.get_name(child);
                if (!obj[nodeName]){
                    obj[nodeName] = this._recursive_traverse(child);
                } else {
                    if (!obj[nodeName].length){
                        var first = obj[nodeName];
                        obj[nodeName] = [];
                        obj[nodeName].push(first);
                    }
                    obj[nodeName].push(this._recursive_traverse(child));
                }
			}, this);
		}
		
		return obj;
	},
	
	get_rootNode: function() {
		return this.xml.documentElement;
	},
	
	get_name: function(node) {
		var name = node.nodeName;
		return name;
	},
	
	get_value: function(node) {
		var value = '';
		switch(this.get_type(node)) {
			case 1:
				value = !Browser.ie ? node.textContent : node.text ;
				break;
			default:
				value = node.nodeValue;
		}
		
		// Convert string values to their respective type.
		//value = Number.from(value) !== null ? Number.from(value) : value; 
		value = this.is_number(value) === true ? Number.from(value) : value; 
		value = value === "true" ? true : value;
		value = value === "false" ? false : value;
		
		return value;
	},
	is_number: function(num){
		return (typeof num == 'string' || typeof num == 'number') && !isNaN(num - 0) && num !== '';
	},
	get_type: function(node) {
		var type = node.nodeType;
		return type;
	},
	
	has_childNodes: function(node) {
		return (!!node.childNodes && node.childNodes.length != 0);
	},
	
	get_children: function(node) {
		if(this.has_childNodes(node)) {
			var children = node.childNodes;
			return children;
		} else return null;
	},
	
	get_childElements: function(node) {
		var chel = this.get_children(node);
		chel = this.filter_byType(chel, 1);
		return chel;
	},
	
	has_attributes: function(node) {
		return (node.attributes && node.attributes.length > 0);
	},
	
	get_attributes: function(node) {
		if(this.has_attributes(node)) {
			var attrs = node.attributes;
			return attrs;
		} else return null;
	},
	
	get_attribute: function(node, attribute) {
		if(this.has_attributes(node)) {
			var attrValue = node.getAttribute(attribute);
			return attrValue;
		} else return null;
	},
	
	collection_toArray: function(nodesCollection) {
		var nodesArray = [];
		Array.each(nodesCollection, function(node) {
			if(this.get_type(node) == 1) {
				nodesArray.append([node]);
			}
		}, this);
		return nodesArray;
	},
	
	filter_byType: function(nodes, type) {
		type = (type != undefined && typeOf(type) == 'number')? type : 1;
		var filteredNodes = this.xml.createElement('filteredNodes');
		for(i=0;i<nodes.length;i++) {
			if(nodes[i].nodeType == type) {
				var newNode = nodes[i].cloneNode(true);
				filteredNodes.appendChild(newNode);
			}
		}
		return filteredNodes.childNodes;
	},
	
	get_fromPath: function(source, path) {
		var parts = path.split('.');
		for (var i = 0, l = parts.length; i < l; i++){
			if (source.hasOwnProperty(parts[i])) {
				source = source[parts[i]];
			} else return null;
		}
		return source;
	},
	
	set_toPath: function(source, path, val) {
		var parts = key.split('.'),
			source2 = source; // so we can return the object
		for (var i = 0, l = parts.length; i < l; i++) {
			// So when the value does not exist (and is an own property) or is not an object
			if (i < (l - 1) && (!source.hasOwnProperty(parts[i]) || !Type.isObject(source[i]))){
				source[parts[i]] = {};
			}

			if (i == l - 1) source[parts[i]] = val;
			else source = source[parts[i]];
		}
		// Return the modified object
		return source2;
	},
	
	// getRequest method
	getRequest: function(xmlurl) {
		var requestOptions = {
			method: 'get',
			url: xmlurl,
			noCache: true,
			onSuccess: function(text, xml) {
							this.text = text;
							this.xml = xml;
							this.root = this.get_rootNode();
							this.xmlObj = this._recursive_traverse(this.root);
							this.complete();
						}.bind(this)
			};
		return this.request ? this.request.setOptions(requestOptions) : this.request = new Request(requestOptions);
	},
	
	complete: function() {
		var obj = {
			xmlObj: this.xmlObj,
			text: this.text,
			xml: this.xml
		};
		
		this.fireEvent('complete', obj);
	}
	
});


FusionCharts = function(fileName, id, width, height){
    /* constructor */
    fileName = fileName.toLowerCase();
    fileNameLength =  fileName.indexOf('.swf')+4 - (fileName.lastIndexOf('/')+1);
    this.type = fileName.substr(fileName.lastIndexOf('/')+1, fileNameLength);
    this.id = id;
    this.width = width;
    this.height = height;
    this.dataObj = {};
};

FusionCharts.prototype = {
    constructor: FusionCharts,
    setDataXML: function(strXml){
        strXml = strXml.replace(/>,/gm,'>');
        
        var xmlDom = this.parseStrXml(strXml);
        var obj = new XML2Object(xmlDom).xmlObj;
        var dataset = [];
        this.dataObj = {};
        
        if (!obj){
            return false;
        }

        switch(this.type){
            case 'pie3d.swf':
                if (obj.set){
                    if (obj.set.length){
                        for(var i=0,j=obj.set.length;i<j;i++){
                            dataset[i] = [obj.set[i]['@attributes'].label, obj.set[i]['@attributes'].value];
                        }
                    }else{
                        dataset[0] = [obj.set['@attributes'].label, obj.set['@attributes'].value];
                    }
                }else{
                    return false;
                }
                
                this.dataObj = {
                    chart: {
                        type: 'pie',
                        // default turn off animation due to performance issue
                        animation: false,
                        reflow: false
                    },
                    title: {
                        text: ''
                    },
                    tooltip: {
                        formatter: function() {
                            return '<b>'+ this.point.name +'</b>: '+ this.y;
                        }
                    },
                    plotOptions: {
                        pie: {
                            allowPointSelect: true,
                            cursor: 'pointer',
                            dataLabels: {
                                enabled: true,
                                color: '#000000',
                                connectorColor: '#000000',
                                formatter: function() {
                                    return '<b>'+ this.point.name +'</b>: '+ this.y;
                                }
                            },
                            showInLegend: true
                        }
                        
                    },
                    series: [{
                        type: 'pie',
                        data: dataset
                    }]
                };
                break;
            case 'msline.swf':
            case 'mscombi3d.swf':
                 var arrCategory = [];
                 if (!obj || !obj.categories || !obj.dataset){
                      return false;
                 }

                 var arrCategoryData = obj.categories.category;
                 for(var i=0,j=arrCategoryData.length;i<j;i++){
                     arrCategory[i] = [arrCategoryData[i]['@attributes']['name']];
                 }
                 var data = obj.dataset;
                 if(data.length){
                     for(var i=0,j=data.length;i<j;i++){
                         var arrValue = [];
                         for(var k=0,l=data[i].set.length;k<l;k++){
                             arrValue[k] = data[i].set[k]['@attributes']['value'];
                         }
                         dataset[i] = {name:"'"+data[i]['@attributes']['seriesName']+"'",data:arrValue};
                     }
                 }else{
                     var arrValue = [];
                     for(var k=0,l=data.set.length;k<l;k++){
                         arrValue[k] = data.set[k]['@attributes']['value'];
                     }
                     dataset[0] = {name:"'"+data['@attributes']['seriesName']+"'",data:arrValue};
                 }

             	var intTickInterval = 1; //default
             	if(arrCategory.length > 14){ // > 2 weeks
                    intTickInterval = 5;
             	}else if(arrCategory.length == 14){
                     intTickInterval = 2;
                }
                this.dataObj = {
                    chart: {
                        type: 'line',
                        // default turn off animation due to performance issue
                        animation: false,
                        reflow: false,
                        plotBorderWidth : 0.5,
                        plotBorderColor:'#666',
                        marginRight :15,
                        marginTop: 20
                    },
                    title: {
                        text: ''
                    },
                    xAxis: {
                        categories: arrCategory,
                        tickmarkPlacement:'on',
                        tickInterval:intTickInterval,
                        tickColor:'#666',
                        labels: {
                            y:20,
                            style: {
                                color:'#333',
                                fontFamily: 'arial',
                                fontSize:12
                            }
                        }
                    },
                    yAxis: {
                         title: {
                             margin:10,
                             text: obj['@attributes']['yAxisName'],
                             style: {
                                 color:'#000',
                                 backgroundColor:'#fff',
                                 fontFamily: 'arial',
                                 fontSize:12,
                                 fontWeight: 'bold'
                             }
                         },
                         labels: {
                             style: {
                                 color:'#333',
                                 fontSize:12,
                                 fontFamily: 'arial'
                             }
                         },
                        allowDecimals:false,
                        gridLineColor:'#ccc',
                        min:0,
                        minRange: 5
                    },
                    legend: {
                        margin:10,
                        itemStyle: {
                            fontFamily: 'arial',
                            fontSize:11
                        },
                        labelFormatter: function() {
                            return this.name.substring(1,this.name.length-1);
                        }
                    },
                    plotOptions: {
                        series: {
                            marker: {
                                lineColor: null,
                                states: {
                                    hover: {
                                        fillColor: '#fff',
                                        lineWidth: 2
                                    }
                                }
                            }
                        }
                    },
                    tooltip: {
                        borderColor:'#999',
                        borderWidth :1,
                        style:{
                            color:'#000',
                            fontFamily: 'arial',
                            fontSize:11
                        },
                        formatter: function() {
                            return '<b>'+ this.series.name.substring(1,this.series.name.length-1) +'</b><br/>'+ this.x +' : '+ this.y;
                        }
                    },
                    series: dataset
                };
                break;
            default: break;
        }
        return true;
    },
    setTransparent: function(isTransparent){
    },
    render: function(container){
        if (!this.dataObj.chart){
            return null;
        }
        
        if (typeof(container) === 'string'){
            container = $(container);
        }
        
        if (!container){
            return null;
        }
        
        // setSize is control by Highcharts
        /*var s = container.getSize();
        var str = JSON.encode(this.dataObj.series);
        
        
        if (container.oldConfig 
            && container.oldConfig.type === this.dataObj.chart.type
            && container.oldConfig.datasetStr === str)
        {
            if (container.oldConfig.size.x !== this.width || container.oldConfig.size.y !== this.height){
                container.highChart.setSize(this.width,this.height);
            } else if (container.oldConfig.parentSize.x !== s.x || container.oldConfig.parentSize.y !== s.y){
                container.highChart.setSize(s.x,s.y);
            }
            return true;
        }*/
        
        if (container.highChart && container.highChart.destroy){
            container.highChart.destroy();
            container.highChart = null;
            if (typeof(CollectGarbage) === 'function'){
                CollectGarbage();
            }
        }
           
        if (this.width){
            this.dataObj.chart.width = typeof(this.width) === 'number' ? this.width : parseInt(this.width);
        }
        if (this.height){
            this.dataObj.chart.height = typeof(this.height) === 'number' ? this.height : parseInt(this.height);
        }
        
        this.dataObj.chart.renderTo = container;
        /*container.oldConfig = {
            type: this.dataObj.chart.type,
            datasetStr: str,
            size: {
                x: this.width,
                y: this.height
            },
            parentSize: {
                x: s.x,
                y: s.y
            }
        };*/
        container.highChart = new Highcharts.Chart(this.dataObj);
        return true;
    },
    parseStrXml:function(xml){
        var xmldom = null;
        if (typeof(ActiveXObject) !== 'undefined'){
            xmldom = this.MSCreateDocument();
            xmldom.loadXML(xml);
            if (xmldom.parseError != 0){
                throw new Error('XML parsing error: ' + xmldom.parseError.reason);
            }
        } else if (typeof(DOMParser) !== 'undefined'){
            xmldom = (new DOMParser()).parseFromString(xml, 'text/xml');
            var errors = xmldom.getElementsByTagName('parseerror');
            if (errors.length){
                throw new Error('XML parsing error: ' + errors[0].textContent);
            }
        } else if (document.implementation.hasFeature('LS', '3.0')){
            var implementation = document.implementation;
            var parser = implementation.createLSParser(implementation.MODE_SYNCHRONOUS, null);
            var input = implementation.createLSInput();
            input.stringData = xml;
            xmldom = parser.parse(input);
        }
        return xmldom;
    },
    MSCreateDocument:function(){
        if (typeof(arguments.callee.activeXString) !== 'string'){
            var versions = ['MSXML2.DOMDocument.6.0', 'MSXML2.DOMDocument.3.0','MSXML2.DOMDocument'];
            for (var i=0,j=versions.length;i<j;++i){
                try {
                    var xmldom = new ActiveXObject(versions[i]);
                    arguments.callee.activeXString = versions[i];
                    return xmldom;
                } catch (ex){
                }
            }
        }
        return new ActiveXObject(arguments.callee.activeXString);
    }
};
